﻿/* ****************************************************************************
* Copyright (c) TCC - 2009 IME - USP. 
*
* This source code is subject to terms and conditions of the Microsoft Public License. 
* A copy of the license can be found in http://msdn.microsoft.com/en-us/library/dd228915.aspx. 
* By using this source code in any fashion, you are agreeing to be bound by the terms of the 
* Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
* ***************************************************************************/

using SoundLibrary.BeatDetection;
namespace SoundLibrary.Converter
{
    public class Frame
    {
        private BitStream frameBuffer;
        private Header header;
        private Mp3Stream source;
        private const int BUFFER_SIZE = 433;
        OBuffer outputBuffer;

        MP3Decoder mp3Decoder;

        public float[] Spectrum
        {
            get { return mp3Decoder.Spectrum; }
        }

        public Frame(Mp3Stream stream, BeatDetector beatDetector)
        {
            this.source = stream;
            this.header = new Header(stream);
            this.frameBuffer = new BitStream(BUFFER_SIZE);
            outputBuffer = new OBuffer();
            mp3Decoder = new MP3Decoder(frameBuffer, header, outputBuffer, (int)OutputChannelsEnum.BOTH_CHANNELS, beatDetector);
        }

        private void LoadFrameBuffer()
        {
            sbyte[] frameBytes = new sbyte[BUFFER_SIZE * 4];
            source.Read(frameBytes, 0, this.header.framesize);
            this.frameBuffer.LoadBytes(frameBytes, this.header.framesize);
        }

        public bool getNextFrame()
        {
            if (!this.header.GetNextHeader())
                return false;
            this.LoadFrameBuffer();
            this.mp3Decoder.DecodeFrame(this.header, this.frameBuffer);
            return true;
        }

        public int Read(byte[] buffer, int offset, int count)
        {
            int bytesRead = 0;
            while (true)
            {
                if (outputBuffer.bytesLeft <= 0)
                {
                    if (!getNextFrame())
                        return 0;
                }

                bytesRead += outputBuffer.Read(buffer, offset + bytesRead, count - bytesRead);

                if (bytesRead >= count)
                    break;
            }
            return bytesRead;
        }
    }
}
